package org.jfsm.demo.ccounter.timer;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.jfsm.core.FSMReplyContext;
import org.jfsm.core.SimpleFSMContext;
import org.jfsm.log.LogSource;

/**
 * For now, this is a delay rather than a timer.
 * 
 * @author x
 * 
 */
public class TimerContext extends SimpleFSMContext implements Runnable {

    TimerRequest callBack;
    FSMReplyContext replyCtx;

    final LogSource logger = new LogSource();

    private final ReentrantLock timeLock = new ReentrantLock();
    private final Condition started = timeLock.newCondition();

    private long ms;

    TimerContext() {
        Thread timer = new Thread(this, "FSM Timer");
        timer.setDaemon(true);
        timer.setPriority(6);
        timer.start();
    }

    final void start(long ms) {
        timeLock.lock();
        this.ms = ms;
        started.signal();
        timeLock.unlock();
    }

    public void run() {
        try {
            for (;;) {
                long sleep;
                logger.log("timer", " waiting");

                timeLock.lock();
                while (ms == 0) {
                    started.await();
                }
                sleep = ms;
                ms = 0;
                timeLock.unlock();

                logger.log("timer sleeping ", sleep);
                timeLock.lock();
                if (started.await(sleep, TimeUnit.MILLISECONDS)) {
                    logger.log("timer interrupted ");
                } else {
                    logger.log("timer", " woke");
                }
                timeLock.unlock();

                callBack.timeout.dispatch(this);
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    @Override
    public String toString() {
        return "FSM Timer";
    }
}
